package com.onlyxiahui.common.action.description;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.onlyxiahui.common.action.description.annotation.DocModule;
import com.onlyxiahui.common.action.description.bean.ModuleData;
import com.onlyxiahui.common.action.description.common.TagConstant;
import com.onlyxiahui.common.action.description.handler.ModuleHandler;
import com.onlyxiahui.common.action.description.handler.impl.BaseModuleHandler;
import com.onlyxiahui.common.action.description.handler.impl.method.ActionMappingMethodHandler;
import com.onlyxiahui.common.action.description.handler.impl.method.RequestMappingMethodHandler;
import com.onlyxiahui.common.action.description.handler.impl.method.RestMappingMethodHandler;
import com.onlyxiahui.common.action.description.handler.impl.module.ActionMappingModuleHandler;
import com.onlyxiahui.common.action.description.handler.impl.module.ControllerModuleHandler;
import com.onlyxiahui.common.action.description.handler.impl.parameter.DefineParameterHandler;
import com.onlyxiahui.common.action.description.handler.impl.parameter.FormParameterHandler;
import com.onlyxiahui.common.action.description.handler.impl.parameter.PathVariableParameterHandler;
import com.onlyxiahui.common.action.description.handler.impl.parameter.RequestBodyParameterHandler;
import com.onlyxiahui.common.action.description.handler.impl.parameter.RequestParamParameterHandler;
import com.onlyxiahui.common.action.description.handler.impl.property.DefaultPropertyHandler;
import com.onlyxiahui.common.action.description.handler.impl.result.DefaultResultHandler;
import com.onlyxiahui.common.action.description.handler.impl.title.MethodCommentTitleHandler;
import com.onlyxiahui.common.action.description.handler.impl.title.MethodSetTitleHandler;
import com.onlyxiahui.common.action.description.handler.impl.title.ModuleCommentTitleHandler;
import com.onlyxiahui.common.action.description.handler.impl.title.ModuleDefineTitleHandler;
import com.onlyxiahui.common.action.description.handler.impl.title.ModuleSetTitleHandler;
import com.onlyxiahui.common.action.description.handler.impl.validate.ValidationParameterValidateHandler;
import com.onlyxiahui.common.action.description.handler.impl.validate.ValidationPropertyValidateHandler;
import com.onlyxiahui.common.action.description.support.DocClassScanner;
import com.onlyxiahui.common.action.description.support.impl.IgnoreJudgeImpl;
import com.onlyxiahui.common.action.description.support.impl.SpringClassScanner;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;

/**
 * Description <br>
 * Date 2020-01-07 14:36:19<br>
 * 
 * @author xiahui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */

public class DocumentService {

	private final DocumentContext documentContext = new DocumentContext(this);

	public DocumentService() {
		initialize();
	}

	public void initialize() {

		documentContext.addModuleHandler(new ControllerModuleHandler());
		documentContext.addModuleHandler(new ActionMappingModuleHandler());

		documentContext.addMethodHandler(new ActionMappingMethodHandler());
		documentContext.addMethodHandler(new RequestMappingMethodHandler());
		documentContext.addMethodHandler(new RestMappingMethodHandler());

		documentContext.addParameterHandler(new DefineParameterHandler());
		documentContext.addParameterHandler(new RequestBodyParameterHandler());
		documentContext.addParameterHandler(new RequestParamParameterHandler());
		documentContext.addParameterHandler(new PathVariableParameterHandler());
		documentContext.addParameterHandler(new FormParameterHandler());
		documentContext.addParameterValidateHandler(new ValidationParameterValidateHandler());

		documentContext.addPropertyHandler(new DefaultPropertyHandler());
		documentContext.addPropertyValidateHandler(new ValidationPropertyValidateHandler());

		documentContext.addModuleTitleHandler(new ModuleDefineTitleHandler());
		documentContext.addModuleTitleHandler(new ModuleSetTitleHandler());
		documentContext.addModuleTitleHandler(new ModuleCommentTitleHandler());

		documentContext.addMethodTitleHandler(new MethodSetTitleHandler());
		documentContext.addMethodTitleHandler(new MethodCommentTitleHandler());

		documentContext.addResultHandler(new DefaultResultHandler());

		documentContext.setDocClassScanner(new SpringClassScanner());

		documentContext.getIgnoreJudgeBox().add(new IgnoreJudgeImpl());
	}

	public void loadSource(String path) {
		documentContext.loadSource(path);
	}

	public void loadSource(String... path) {
		documentContext.loadSource(path);
	}

	public List<ModuleData> scanPackages(String... paths) {
		DocClassScanner cs = documentContext.getDocClassScanner();
		List<ModuleData> list = new ArrayList<>();
		Map<String, Class<?>> classMap = new HashMap<>(256);
		if (null != cs) {
			Set<Class<?>> classSet = cs.scan(paths);
			for (Class<?> classType : classSet) {
				ModuleData md = handler(classType);
				if (null != md) {
					list.add(md);
				} else {
					if (!documentContext.getIgnoreJudgeBox().ignore(documentContext, classType)) {
						// 未识别的模块
						classMap.put(classType.getName(), classType);
					}
				}
			}
		}
		BaseModuleHandler bm = new BaseModuleHandler() {

			@Override
			public boolean support(DocumentContext context, Class<?> moduleClass) {
				return false;
			}

			@Override
			public ModuleData handle(DocumentContext context, Class<?> moduleClass) {
				return null;
			}

		};
		Map<String, JavaClass> map = documentContext.getSourceBox().getJavaFileMap();
		for (Map.Entry<String, Class<?>> e : classMap.entrySet()) {
			Class<?> classType = e.getValue();
			if (null != classType) {
				String className = classType.getName();
				DocModule dmd = classType.getAnnotation(DocModule.class);
				JavaClass jc = map.get(className);

				boolean hasJava = false;

				if (null != jc) {
					DocletTag keyTag = jc.getTagByName(TagConstant.DOC_MODULE_KEY);
					if (null != keyTag) {
						hasJava = true;
					}
				}

				if (null != dmd || hasJava) {
					ModuleData md = bm.create(documentContext, classType, new ArrayList<>());
					if (null != md) {
						list.add(md);
					}
				}
			}
		}
		return list;
	}

	public ModuleData handler(Class<?> clazz) {
		if (null != clazz) {
			for (ModuleHandler moduleHandler : documentContext.getModuleHandlers()) {
				if (documentContext.getIgnoreJudgeBox().ignore(documentContext, clazz)) {
					continue;
				}
				if (moduleHandler.support(documentContext, clazz)) {
					return moduleHandler.handle(documentContext, clazz);
				}
			}
		}
		return null;
	}

	public DocumentContext getDocumentContext() {
		return documentContext;
	}

	public void clear() {
		documentContext.clear();
	}
}
